/**
 * @class   wosh::List
 * @brief   Generic List holder, real data is stored as string.
 *
 * @ingroup DataModels
 ****************************************************************************
 * @version $Id: List.h 2863 2010-08-07 04:28:58Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_List_H__
 #define __WOSH_Core_List_H__

 #include <woshDefs.h>
 #include <core/Containers.h>
 #include <core/Variant.h>
 #include <core/Mutex.h>
 #include <core/Serialization.h>


namespace wosh {

class List : public ListT<ISerializable*>, public ISerializable
 {
	WOSH_SERIALIZABLE(wosh::List)
	WOSH_COMPARE_RTTI(wosh::List)


	public:
		/**
		 * @brief  Empty constructor.
		 */
		List() : ListT<ISerializable*>() { }
		/**
		 * @brief  Constructor with initializer, reserve some slots.
		 * @param reserve_size [in] number of items of the list (projected)
		 * @see    reserve()
		 */
		List( int reserve_size ) : ListT<ISerializable*>() {
			reserve(reserve_size);
		 }
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		List( const List& m ) : ListT<ISerializable*>() {
			*this = m;
		 }
		/**
		 * @brief  Destructor. Free elements!
		 */
		virtual ~List() {
			free();
		 }


	public:

		// usage: push<Variant>( "asd" ); // no memory waste
		template <class PROXY, typename TYPE>
		void push_back( const TYPE& object ) {
			this->list.push_back( new PROXY(object) );
		 }

		using ListT<ISerializable*>::push_back;

//		// specialization of - (default of previous)
// VEDI TABLE!
//		template <typename TYPE>
//		void push_back( const TYPE& object ) {
//			this->list.push_back( new Variant(object) ); // should be: new TYPE(object)
//		 }

/** @name Getters
 * @{
 ******************************************************************************/
	public:

		template <typename MAP_KEY, typename MAP_VALUE>
		void fromMapKey( const std::map<MAP_KEY,MAP_VALUE>& input_map ) {
			typename std::map<MAP_KEY,MAP_VALUE>::const_iterator it;
			for ( it=input_map.begin(); it!=input_map.end(); ++it ) {
				push_back( it->first );
			 }
		 }

		template <typename MAP_KEY, typename MAP_VALUE>
		void fromMapValue( const std::map<MAP_KEY,MAP_VALUE>& input_map ) {
			typename std::map<MAP_KEY,MAP_VALUE>::const_iterator it;
			for ( it=input_map.begin(); it!=input_map.end(); ++it ) {
				push_back( it->second );
			 }
		 }
		template <typename MAP_KEY, typename MAP_VALUE>
		void fromMapValue( const std::map<MAP_KEY,MAP_VALUE*>& input_map, bool deep_copy ) {
			typename std::map<MAP_KEY,MAP_VALUE*>::const_iterator it;
			for ( it=input_map.begin(); it!=input_map.end(); ++it ) {
				if ( it->second == NULL ) continue;
				if ( deep_copy )
					this->list.push_back( it->second->clone() );
				else
					this->list.push_back( it->second );
			 }
		 }

		int search( const ISerializable* value, short compare_mode = 0 ) {
			int i = 0;
			ConstIterator it;
			for ( it=this->list.begin(); it!=this->list.end(); ++it, ++i ) {
				if ( *it == value ) return i;
				if ( *it == NULL ) continue;
				if ( (*it)->compare(value) == compare_mode ) return i;
			 }
			return -1;
		 }

// BUG : OLD TO REVIEW
		template <typename T>
		void fromVector( std::vector<T>& values ) {
			transactionBeginWrite();
			free();
			typename std::vector<T>::const_iterator it;
			for ( it=values.begin(); it!=values.end(); ++it ) {
				this->list.push_back( new Variant(*it) );
			 }
			transactionEnd();
		 }

		template <typename T_CAST>
		inline std::vector<T_CAST*> getVector() const {
			typename std::vector<T_CAST*> outvector;
			ConstIterator it;
			const ConstIterator it_end = this->list.end();
			for ( it=this->list.begin(); it!=it_end; ++it ) {
				if ( *it == NULL ) {
					outvector.push_back(NULL);
					continue;
				 }
				const T_CAST* tc = dynamic_cast<const T_CAST*>(*it);
				if ( tc == NULL ) {
					outvector.push_back( NULL );
					continue;
				 }
				outvector.push_back( dynamic_cast<T_CAST*>(tc->clone()) );
			 }
			return outvector;
		 }

		using ListT<ISerializable*>::getVector;

		template <typename TYPE1>
		static List* createFill( TYPE1* obj1 ) {
			List* nl = new List(1);
			nl->list.push_back( obj1 );
			return nl;
		 }
		template <typename TYPE1, typename TYPE2>
		static List* createFill( TYPE1* obj1, TYPE2* obj2 ) {
			List* nl = new List(2);
			nl->list.push_back( obj1 );
			nl->list.push_back( obj2 );
			return nl;
		 }
		template <typename TYPE1, typename TYPE2, typename TYPE3>
		static List* createFill( TYPE1* obj1, TYPE2* obj2, TYPE3* obj3 ) {
			List* nl = new List(3);
			nl->list.push_back( obj1 );
			nl->list.push_back( obj2 );
			nl->list.push_back( obj3 );
			return nl;
		 }

		// usage: createFrom<Variant>( "asd" ); // no memory waste
		template <class PROXY, typename TYPE1>
		static List* createFrom( const TYPE1& obj1 ) {
			List* nl = new List(1);
			nl->list.push_back( new PROXY(obj1) );
			return nl;
		 }
		// usage: createFrom<Variant>( "asd", 1234 ); // no memory waste
		template <class PROXY, typename TYPE1, typename TYPE2>
		static List* createFrom( const TYPE1& obj1, const TYPE2& obj2 ) {
			List* nl = new List(2);
			nl->list.push_back( new PROXY(obj1) );
			nl->list.push_back( new PROXY(obj2) );
			return nl;
		 }
		// usage: createFrom<Variant>( "asd", 1234 ); // no memory waste
		template <class PROXY, typename TYPE1, typename TYPE2, typename TYPE3>
		static List* createFrom( const TYPE1& obj1, const TYPE2& obj2, const TYPE3& obj3 ) {
			List* nl = new List(3);
			nl->list.push_back( new PROXY(obj1) );
			nl->list.push_back( new PROXY(obj2) );
			nl->list.push_back( new PROXY(obj3) );
			return nl;
		 }

		void toVectorString( std::vector<std::string>& values ) const {
			transactionBeginRead();
			ConstIterator it;
			const ConstIterator it_end = this->list.end();
			for ( it=this->list.begin(); it!=it_end; ++it ) {
				if ( *it == NULL ) continue;
				values.push_back( (*it)->toString() );
			 }
			transactionEnd();
		 }

//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:
		int cleanNULLs() {
			int count = 0;
			Iterator it = this->list.begin();
			while( it != this->list.end() ) {
				if ( *it != NULL ) { ++it; continue; }
				it = this->list.erase(it);
				++count;
			 }
			return count;
		 }

//@}
/** @name Search methods
 * @{
 ******************************************************************************/
	public:
		int findItem( const ISerializable* other, short compare_mode = 0 ) const {
			int index = 0;
			ConstIterator it;
			for ( it=this->list.begin(); it!=this->list.end(); ++it, ++index ) {
				if ( *it == other && compare_mode == -1 ) return index;
				if ( *it == NULL ) continue;
				if ( (*it)->compare(other) == compare_mode ) return index;
			 }
			return -1;
		 }
		int countItems( const ISerializable* other, short compare_mode = 0 ) const {
			int count = 0;
			ConstIterator it;
			for ( it=this->list.begin(); it!=this->list.end(); ++it ) {
				if ( *it == other && compare_mode == -1 ) { ++count; continue; }
				if ( *it == NULL ) continue;
				if ( (*it)->compare(other) == compare_mode ) ++count;
			 }
			return count;
		 }

		inline int findItem( const Variant& other ) const {
			return findItem( &other, 0 );
		 }

//@}
/** @name Operators Overloading
 * @{
 ******************************************************************************/
	public:
		virtual List& operator=( const List& m ) {
			if (this == &m) return *this; // same object?
			m.transactionBeginRead();
			transactionBeginWrite();
			free();
			this->list.reserve( m.size() );
			ConstIterator it;
			for ( it=m.list.begin(); it!=m.list.end(); ++it ) {
				if ( *it == NULL ) continue;
				this->list.push_back( (*it)->clone() );
			 }
			transactionEnd();
			m.transactionEnd();
			return *this;
		 }

//@}
/** @name Serialization interface
 * @{
 ******************************************************************************/
	public:
		virtual std::string toString() const;
		virtual bool updateHash( DataHashContext* hash_context ) const;
//@}


}; // class def


}; // namespace wosh

#endif //__WOSH_Core_List_H__
